use sysinfo::{SystemExt, System, ProcessExt,Pid};
use tabled::{Tabled, Table, Style, Footer};

//打印all_processes数组中指定名称的进程的内存信息
//按照ProcessInfo中name字段过滤
pub fn print_process_info_by_name(name: &str, process_info_vec: &[ProcessInfo]) {
    let mut process_info_vec = process_info_vec.to_vec();
    process_info_vec.retain(|process_info| process_info.name == name);
    print_provesses_vector(&process_info_vec); 
}

//打印all_processes数组中指定pid的进程的内存信息
//按照ProcessInfo中pid字段过滤
pub fn print_process_info_by_pid(pid: &Pid, process_info_vec: &[ProcessInfo]) {
    let mut process_info_vec = process_info_vec.to_vec();
    process_info_vec.retain(|process_info| process_info.pid == *pid);
    print_provesses_vector(&process_info_vec); 
}

//打印制定 slice 的内存信息
pub fn print_provesses_vector(process_info_vec: &[ProcessInfo])
{
    let footer = format!("进程总数 {}\n内存总和 {}",
    process_info_vec.len(),
    display_memory(&sum_memory(&process_info_vec)));

    // tabled 打印 
    let table = Table::new(process_info_vec)
        .with(Style::dots())
        .with(Footer(footer))
        .to_string();
    println!("{}", table); 
}

// 根据memory 大小，打印不同的单位
// memory 的默认单位是 KB 
fn display_memory(memory: &u64) -> String {
    let kb = 1;
    let mb = 1024 * kb;
    let gb = 1024 * mb;
    if *memory > gb {
        format!("{:.2} GB", *memory as f64 / gb as f64)
    } else if *memory > mb {
        format!("{:.2} MB", *memory as f64 / mb as f64)
    } else if *memory > kb {
        format!("{:.2} KB", *memory as f64 / kb as f64)
    } else {
        format!("{}", *memory)
    }
}


// 保存进程关键信息
// tabled 相关用法  https://crates.io/crates/tabled#Settings
#[derive(Debug, Tabled, Clone)]
#[allow(dead_code)]
pub struct ProcessInfo {
    
    #[header("进程ID")]
    pid: Pid,

    #[header("进程名")]
    name: String,

    #[field(display_with = "display_memory")] // 使用 display_memory 函数返回字符串
    #[header("内存")]
    memory: u64,

    #[header(hidden = true)] // table中不显示 cpu_usage 列
    cpu_usage: f64,
}

impl ProcessInfo {
    fn new(pid: sysinfo::Pid, name: String, cpu_usage: f64, memory: u64) -> ProcessInfo {
        ProcessInfo {
            pid,
            name,
            cpu_usage,
            memory,
        }
    }
}


pub fn get_all_processinfo() -> Vec<ProcessInfo> {
    let mut process_info_vec = Vec::new();
    let system = System::new_all();
    let processes = system.processes();
    for process in processes.values() {
        let pid = process.pid();
        let name = process.name().to_string();
        let cpu_usage = process.cpu_usage() as f64;
        let memory = process.memory();
        let process_info = ProcessInfo::new(pid, name, cpu_usage, memory);
        process_info_vec.push(process_info);
    }

    // 根据memory排序，从大到小
    process_info_vec.sort_by(|a, b| b.memory.cmp(&a.memory));
    process_info_vec
}


// 获取所有进程 memory 总和
fn sum_memory(process_info_vec: &[ProcessInfo]) -> u64 {
    let mut sum = 0;
    for process_info in process_info_vec {
        sum += process_info.memory;
    }
    sum
}
